package com.oocl.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.border.LineBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.oocl.communicator.Sender;
import com.oocl.communicator.impl.ReceiverImpl;
import com.oocl.communicator.impl.SenderImpl;
import com.oocl.constant.LogLevel;
import com.oocl.constant.ProtocolType;
import com.oocl.parser.ProtocolParser;
import com.oocl.pojo.Protocol;
import com.oocl.util.LogUtil;
import com.oocl.util.DateUtil;
import com.oocl.util.ResourceReleaser;

/**
 * 
 * @author ZHANGAR
 *
 */
@SuppressWarnings("serial")
public class ChatFrame extends JFrame implements ActionListener, ProtocolParser {
	private JTextArea chatTa;
	private JTextArea friendsTa;
	private JTextField sendTf;
	private JButton sendBtn;
	private JButton shakeBtn;
	private JList<String> jList;
	private DefaultListModel<String> listModel;
	private JButton allButton;

	private Socket socket;
	ReceiverImpl receiver;
	Sender sender;
	BufferedReader in;
	PrintWriter out;
	private String username;
	// 添加内容
	private ArrayList<String> onlineUsers;
	private String chatObject;

	public ChatFrame(Socket socket, BufferedReader in,
			PrintWriter out, String username, ArrayList<String> arrayList) {
		this.setTitle(username);
		this.socket = socket;
		this.in = in;
		this.out = out;
		this.username = username;
		this.onlineUsers = arrayList;

		this.setTitle(username);
		this.setSize(500, 340);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setLocationRelativeTo(null);
		init();
		addEvent();
		this.setVisible(true);

		initResource();
	}

	private void initResource() {
		sender = new SenderImpl(out);
		receiver = new ReceiverImpl(in, this);
		receiver.start();
	}

	public ChatFrame() {
		this.setSize(400, 300);
		this.setLocationRelativeTo(null);
		init();
		addEvent();
		this.setVisible(true);
	}

	@SuppressWarnings("unchecked")
	private void init() {
		this.setLayout(new BorderLayout());
		JPanel panLeft = new JPanel(new BorderLayout());
		JPanel panRight = new JPanel(new BorderLayout());
		JPanel panLeftBottom = new JPanel(new BorderLayout());
		JPanel panBtnGroup = new JPanel(new BorderLayout());

		chatTa = new JTextArea(10, 20);
		friendsTa = new JTextArea(10, 10);
		sendTf = new JTextField();
		sendBtn = new JButton("send");
		shakeBtn = new JButton("shake");
		allButton = new JButton("All user");

		sendTf.setFont(new Font("宋体", Font.BOLD, 18));
		sendTf.setForeground(Color.red);

		chatTa.setFont(new Font("宋体", Font.BOLD, 18));
		chatTa.setForeground(Color.blue);
		chatTa.setEditable(false);
		panRight.add(friendsTa, BorderLayout.CENTER);
		panLeft.add(new JScrollPane(chatTa), BorderLayout.CENTER);
		panLeft.add(panLeftBottom, BorderLayout.SOUTH);
		panRight.setBorder(new LineBorder(Color.red));
		panRight.add(allButton, BorderLayout.NORTH);

		listModel = new DefaultListModel<String>();
		for (int i = 0; i < onlineUsers.size(); i++) {
			listModel.addElement(onlineUsers.get(i));
		}
		jList = new JList<>();
		jList.setModel(listModel);
		jList.setCellRenderer(new MyCellRender());
	    jList.setFixedCellHeight(23);
		JScrollPane rightScrollPane = new JScrollPane();
		rightScrollPane.setPreferredSize(new Dimension(80, 100));
		rightScrollPane.setViewportView(jList);
		panRight.add(rightScrollPane, BorderLayout.CENTER);

		this.add(panLeft, BorderLayout.CENTER);
		this.add(panRight, BorderLayout.EAST);
		panBtnGroup.add(shakeBtn, BorderLayout.NORTH);
		panBtnGroup.add(sendBtn, BorderLayout.SOUTH);
		panLeftBottom.add(sendTf, BorderLayout.CENTER);
		panLeftBottom.add(panBtnGroup, BorderLayout.EAST);
	}

	private void addEvent() {

		sendBtn.addActionListener(this);
		this.addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				try {
					Protocol protocol = new Protocol();
					protocol.setType(ProtocolType.LAYOUT);
					protocol.setFrom(username);
					protocol.setTime(new Date());
					sender.send(protocol);
				} catch (IOException e1) {
					LogUtil.log("IOException!"+e1.getMessage(), LogLevel.ERROR);
					ResourceReleaser.release(out, in, socket);
				}
			}

		});

		// 将鼠标点中的登录用户显示在控制台。
		jList.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				if (!jList.getValueIsAdjusting()) { // 设置只有释放鼠标时才触发
					ChatFrame.this.setTitle(username + " To "
							+ jList.getSelectedValue());
					chatObject = (String) jList.getSelectedValue();
				}
			}
		});
		allButton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				jList.setModel(listModel);
				chatObject = "all";
				ChatFrame.this.setTitle(username + " To all");
			}
		});
		shakeBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {

				if (chatObject == null || "".equals(chatObject)) {
					JOptionPane.showMessageDialog(null,
							"You have to select someone to shake", "Tip",
							JOptionPane.ERROR_MESSAGE);
					return;
				}
				if (chatObject.equals(username)) {
					JOptionPane.showMessageDialog(null,
							"You can not shake yourself", "Tip",
							JOptionPane.ERROR_MESSAGE);
					return;
				}

				Protocol protocol = new Protocol();
				if ("all".equals(chatObject)) {
					protocol.setType(ProtocolType.GROUP_SHAKE);
				} else {
					protocol.setType(ProtocolType.PRIVATE_SHAKE);
				}
				protocol.setTime(new Date());
				protocol.setFrom(username);
				protocol.setTo(chatObject);

				try {
					sender.send(protocol);
				} catch (IOException e1) {
					LogUtil.log("IOException!"+e1.getMessage(), LogLevel.ERROR);
					ResourceReleaser.release(out, in, socket);
				}
			}
		});
	}


	@Override
	public void actionPerformed(ActionEvent e) {
		if (chatObject == null || "".equals(chatObject)) {
			JOptionPane.showMessageDialog(null,
					"You have to select someone to talk", "Tip",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		if (chatObject.equals(username)) {
			JOptionPane.showMessageDialog(null, "You can not talk to yourself",
					"Tip", JOptionPane.ERROR_MESSAGE);
			return;
		}
		if (sendTf.getText() == null || "".equals(sendTf.getText())) {
			JOptionPane.showMessageDialog(null, "Please input your message",
					"Tip", JOptionPane.ERROR_MESSAGE);
			return;
		}
		Protocol protocol = new Protocol();
		if ("all".equals(chatObject)) {
			protocol.setType(ProtocolType.GROUPE_TALK);
		} else {
			protocol.setType(ProtocolType.PRIVATE_TALK);
		}
		String content = sendTf.getText();
		String dateString = DateUtil.dateToStr(new Date(), "HH:mm:ss");
		chatTa.append("[" + dateString + "]you said to " + chatObject + "=>"
				+ content + "\n");
		protocol.setTime(new Date());
		protocol.setFrom(username);
		protocol.setTo(chatObject);
		protocol.setContent(sendTf.getText());

		try {
			sender.send(protocol);
		} catch (IOException e1) {
			LogUtil.log("IOException!"+e1.getMessage(), LogLevel.ERROR);
			ResourceReleaser.release(out, in, socket);
		}

	}

	@Override
	public void parsePrivateTalk(Protocol protocol) {
		String dateString = DateUtil.dateToStr(new Date(), "HH:mm:ss");
		chatTa.append("[" + dateString + "]" + protocol.getFrom()
				+ " said to you=>" + protocol.getContent() + "\n");
	}

	@Override
	public void parseGroupTalk(Protocol protocol) {
		String dateString = DateUtil.dateToStr(new Date(), "HH:mm:ss");
		chatTa.append("[" + dateString + "]" + protocol.getFrom()
				+ " said to all=>" + protocol.getContent() + "\n");
	}

	@Override
	public void parsePrivateShake(Protocol protocol) {
		shakeFrame();
	}

	@Override
	public void parseGroupShake(Protocol protocol) {
		shakeFrame();
	}

	@Override
	public void parseLoyout(Protocol protocol) {
		receiver.setRunning(false);
		LogUtil.log("layout secess", LogLevel.INFO);
	}

	@Override
	public void parseUserLogin(Protocol protocol) {
		chatTa.append("---------user " + protocol.getFrom()
				+ " login-----------\n");
		listModel.addElement(protocol.getFrom());
	}

	@Override
	public void parseUserLoyout(Protocol protocol) {
		chatTa.append("---------user " + protocol.getFrom()
				+ " layout-----------\n");
		listModel.removeElement(protocol.getFrom());
	}

	@Override
	public void parseError(Protocol protocol) {
		// TODO Auto-generated method stub

	}
	
	private void shakeFrame() {
		final Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			long stop = 0;
			int count = 0;
			int x = ChatFrame.this.getLocation().x;
			int y = ChatFrame.this.getLocation().y;

			@Override
			public void run() {
				stop += 20;
				count++;
				if (stop >= 600) {
					timer.cancel();
				}
				if (count % 2 == 0) {
					ChatFrame.this.setLocation(x + 5, y + 5);
				} else {
					ChatFrame.this.setLocation(x - 5, y - 5);
				}
			}
		}, 1, 20);
	}

	@SuppressWarnings("rawtypes")
	class MyCellRender extends JLabel implements ListCellRenderer {

		public MyCellRender() {
			setOpaque(true);
		}

		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			setText(value.toString());
			this.setHorizontalAlignment(JLabel.CENTER);
			if (isSelected) {
				setBackground(Color.GRAY);
				setForeground(Color.GREEN);
			} else {
				setBackground(Color.white);
				setForeground(Color.BLUE);
			}
			return this;
		}

	}
}
